﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Model;

namespace StockFinder.Services.StockPerformance
{
    /// <summary>
    /// Finds all moves from new high and then draw down in stock history
    /// </summary>
    public class NewHighBreakoutAndDrawdownPerformanceMoveAnalyser
    {
        public List<StockPerformanceMove> AnalysePrices(List<DailyPrice> prices)
        {
            List<StockPerformanceMove> moves = new List<StockPerformanceMove>();
            decimal previousHighPrice = 0;
            decimal drawDownLowPrice = 0;
            int daysInCurrentMove = 0;
            bool isInDrawdown = true;
            DailyPrice lastMoveStartPrice = null;
            DailyPrice dailyPrice = null;

            var orderedPrices = prices.OrderBy(p => p.PriceDate);

            for (int i = 0; i < orderedPrices.Count(); i++)
            {
                dailyPrice = orderedPrices.ElementAt(i);

                if (i == 0)
                {
                    lastMoveStartPrice = dailyPrice;
                }
                else if (i == 1)
                {
                    if (dailyPrice.AdjustedClose < lastMoveStartPrice.AdjustedClose)
                    {
                        isInDrawdown = true;
                        drawDownLowPrice = dailyPrice.AdjustedClose;
                        previousHighPrice = lastMoveStartPrice.AdjustedClose;
                    }
                    else
                    {
                        isInDrawdown = false;
                        previousHighPrice = dailyPrice.AdjustedClose;
                        drawDownLowPrice = lastMoveStartPrice.AdjustedClose;
                    }

                    daysInCurrentMove++;
                }
                else
                {
                    if (isInDrawdown)
                    {
                        /* DRAW DOWN */

                        if (dailyPrice.AdjustedClose == previousHighPrice)
                        {
                            //no change, just add a day
                            daysInCurrentMove++;
                        }
                        else if (dailyPrice.AdjustedClose > previousHighPrice)
                        {
                            //new uptrend?
                            var drawDown = ((previousHighPrice - drawDownLowPrice) / previousHighPrice) * 100;

                            moves.Add(new StockPerformanceMove()
                            {
                                IsDrawDown = true,
                                DaysOfMove = daysInCurrentMove,
                                MoveAmount = drawDown,
                                StartDate = lastMoveStartPrice.PriceDate
                            });
                            //Debug.WriteLine(string.Format("Previous draw down finished with {0}% move for {1} days", Math.Round(drawDown, 2), daysInCurrentMove));

                            isInDrawdown = false;
                            daysInCurrentMove = 1;
                            lastMoveStartPrice = dailyPrice;
                            drawDownLowPrice = previousHighPrice;
                            previousHighPrice = dailyPrice.AdjustedClose;

                        }
                        else if (dailyPrice.AdjustedClose < drawDownLowPrice)
                        {
                            //new low price?
                            drawDownLowPrice = dailyPrice.AdjustedClose;
                            daysInCurrentMove++;
                        }
                        else
                        {
                            daysInCurrentMove++;
                        }
                    }
                    else
                    {
                        /* UP-MOVE */

                        if (dailyPrice.AdjustedClose == previousHighPrice)
                        {
                            //no change, just add a day
                            daysInCurrentMove++;
                        }
                        else if (dailyPrice.AdjustedClose > previousHighPrice)
                        {
                            //higher uptrend?
                            previousHighPrice = dailyPrice.AdjustedClose;
                            daysInCurrentMove++;
                        }
                        else if (dailyPrice.AdjustedClose < previousHighPrice)
                        {
                            //new draw down - log previous up move
                            var upMove = ((previousHighPrice - drawDownLowPrice) / drawDownLowPrice) * 100;

                            moves.Add(new StockPerformanceMove()
                            {
                                IsDrawDown = false,
                                DaysOfMove = daysInCurrentMove,
                                MoveAmount = upMove,
                                StartDate = lastMoveStartPrice.PriceDate
                            });

                            //Debug.WriteLine(string.Format("Previous Up move finished with {0}% move for {1} days", Math.Round(upMove, 2), daysInCurrentMove));

                            //setup for new draw down
                            lastMoveStartPrice = dailyPrice;
                            isInDrawdown = true;
                            drawDownLowPrice = dailyPrice.AdjustedClose;
                            daysInCurrentMove = 1;
                        }
                        else
                        {
                            daysInCurrentMove++;
                        }
                    }
                }
            }

            if (isInDrawdown)
            {
                var drawDown = ((previousHighPrice - drawDownLowPrice) / previousHighPrice) * 100;

                moves.Add(new StockPerformanceMove()
                {
                    IsDrawDown = true,
                    DaysOfMove = daysInCurrentMove,
                    MoveAmount = drawDown,
                    StartDate = lastMoveStartPrice.PriceDate
                });
                //Debug.WriteLine(string.Format("Currently in a draw down of {0}% for {1} days", Math.Round(drawDown, 2), daysInCurrentMove));
            }
            else
            {
                //new draw down - log previous up move
                var upMove = ((previousHighPrice - drawDownLowPrice) / drawDownLowPrice) * 100;

                moves.Add(new StockPerformanceMove()
                {
                    IsDrawDown = false,
                    DaysOfMove = daysInCurrentMove,
                    MoveAmount = upMove,
                    StartDate = lastMoveStartPrice.PriceDate
                });
                //Debug.WriteLine(string.Format("Currently in a {0}% move for {1} days", Math.Round(upMove, 2), daysInCurrentMove));
            }

            return moves;
        }
    }
}
